function deepClone(obj,map = new WeakMap()) {
  // 对set进行处理
  if(obj instanceof Set) {
    return new Set([...obj])
  }
  // 对map进行处理
  if(obj instanceof Map) {
    return new Map([...obj])
  }
  // 如果值是symbol
  if(typeof obj === "symbol") {
    return Symbol(obj.description)
  }
  // 不是object类型直接将值返回
  if(typeof obj !== "object") {
    return obj
  }
  // 防止循环引用递归导致栈溢出
  if (map.has(obj)) {
    return map.get(obj)
  }
  const newObj = Array.isArray(obj) ? [] : {}
  map.set(obj,newObj)
  for(const key in obj) {
    newObj[key] = deepClone(obj[key],map)
  }
  // 对symbol的key进行处理
  const symbolKey = Object.getOwnPropertySymbols(obj)
  symbolKey.forEach(item => {
    newObj[item] = deepClone(obj[item],map)
  })
  return newObj
}

let s1 = Symbol("aaa")
let s2 = Symbol("bbb")
const obj = {
  name: "why",
  age: 18,
  friend: {
    name: "james",
    friend:"hhhhh",
    address: {
      city: "广州"
    }
  },
  // 数组类型
  hobbies: ["abc", "cba", "nba"],
  // 函数类型
  foo: function(m, n) {
    console.log("foo function")
    console.log("100代码逻辑")
    return 123
  },
  // Symbol作为key和value
  [s1]: "abc",
  s2: s2,
  s3:Symbol(),
  // Set/Map
  set: new Set(["aaa", "bbb", "ccc"]),
  map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}
// 循环引用
obj.info = obj

const deepObj = deepClone(obj)
console.log(deepObj);